﻿namespace MicroCloud.Utils
{
    /// <summary>
    /// 表达式对象转换器
    /// </summary>
    /// <typeparam name="TTarget">要转换的目标对象类型</typeparam>
    public class ExpressionObjectConverter<TTarget> : ExpressionVisitor
        where TTarget : class
    {
        #region "属性"
        #region "获取或设置 表达式参数"
        /// <summary>
        /// 获取或设置 表达式参数
        /// </summary>
        private ParameterExpression Parameter { get; set; }
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个表达式对象转换器的新实例"
        /// <summary>
        /// 初始化一个表达式对象转换器的新实例
        /// </summary>
        public ExpressionObjectConverter()
        {
            var parameter = Expression.Parameter(typeof(TTarget), "m");
            Parameter = parameter;
        }
        #endregion

        #endregion

        #region "方法"
        #region "修改表达式"
        /// <summary>
        /// 修改表达式
        /// </summary>
        /// <param name="expression">待修改的表达式</param>
        /// <returns>修改后的表达式</returns>
        public Expression Modify(Expression expression)
        {
            return Visit(expression);
        }
        #endregion

        #endregion

        #region "受保护的方法"
        #region "Visits the children of the <see cref="Expression{T}"/>."
        /// <summary>
        /// Visits the children of the <see cref="Expression{T}"/>.
        /// </summary>
        /// <typeparam name="T">The type of the delegate.</typeparam>
        /// <param name="node">The expression to visit.</param>
        /// <returns>The modified expression, if it or any subexpression was modified;
        /// otherwise, returns the original expression.</returns>
        protected override Expression VisitLambda<T>(Expression<T> node)
        {
            return Expression.Lambda(Traverse(node.Body), Parameter);
        }
        #endregion

        #endregion

        #region "私有方法"
        #region "遍历转换表达式"
        /// <summary>
        /// 遍历转换表达式
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns>转换后的表达式</returns>
        private Expression Traverse(Expression expression)
        {
            //二无表达式的处理
            if (expression is BinaryExpression)
            {
                var left = Traverse((expression as BinaryExpression).Left);
                var right = Traverse((expression as BinaryExpression).Right);
                return Expression.MakeBinary((expression as BinaryExpression).NodeType, left, right);
            }
            //成员表达式的处理
            if (expression is MemberExpression)
            {
                MemberExpression me = Expression.Property(Parameter, (expression as MemberExpression).Member.Name);
                return me;
            }
            //常量表达式的处理
            if (expression is ConstantExpression)
            {
                return expression;
            }
            //方法调用表达式的处理
            if (expression is MethodCallExpression)
            {
                var mcExpression = expression as MethodCallExpression;
                var body = Traverse(mcExpression.Object);

                return Expression.Call(body, mcExpression.Method, mcExpression.Arguments);
            }
            return expression;
        }
        #endregion

        #endregion

    }

}
